#ifndef UUID_F0440F0C6AB54F026AC6BDBFE986D202
#define UUID_F0440F0C6AB54F026AC6BDBFE986D202

#include <vector>
#include <map>
#include "link.hpp"
#include "utility.hpp"

namespace Psync5
{

struct Packet;

struct Node : NonCopyable
{
	typedef gvl::list<Link>::range LinkRange;

	//friend struct Link;

	Node()
	: serverLink_(0)
	, nextLinkId(0)
	, port(-1)
	, acceptConnections_(false)
	, automaticPacketSending_(true)
	, packetDebug(false)
	{
		gvl::init_sockets();
	}

	~Node()
	{
		gvl::deinit_sockets();
	}

	void initSockets(int port);
	void host(int port);
	Link* connect(char const* address, int port);
	void process();

	virtual void onLinkConnected(Link& link)
	{}

	virtual void onLinkDisconnected(Link& link)
	{}

	virtual Link* newLink(Node* nodeInit, int idInit, gvl::internet_addr const& addrInit, gvl::socket sockInit)
	{ return new Link(nodeInit, idInit, addrInit, sockInit); }

	Link* serverLink()
	{ return serverLink_; }

	Link* linkFromId(int id)
	{
		LinkFromIdMap::iterator i = linkFromId_.find(id);
		if(i == linkFromId_.end())
			return 0;
		return i->second;
	}

	void acceptConnections(bool f)
	{ acceptConnections_ = f; }

	LinkRange allLinks()
	{ return links.all(); }

	void send(Packet const& packet, gvl::internet_addr const& addr);

	bool automaticPacketSending()
	{ return automaticPacketSending_; }

	void automaticPacketSending(bool f)
	{ automaticPacketSending_ = f; }

private:
	Link* findLink_(gvl::internet_addr addr);
	Link* addLink_(gvl::internet_addr addr);

	// Established links
	gvl::list<Link> links;
	Link* serverLink_;

	typedef std::map<int, Link*> LinkFromIdMap;

	LinkFromIdMap linkFromId_;

	int nextLinkId;
	int port;
	gvl::socket sock;
	bool acceptConnections_;
	bool automaticPacketSending_;

	// Debug
	bool packetDebug;
};

}

#endif // UUID_F0440F0C6AB54F026AC6BDBFE986D202
